/*
 *	LoopingMidiPlayer15.java
 *
 *	This file is part of jsresources.org
 */

/*
 * Copyright (c) 1999 - 2001 by Matthias Pfisterer
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
|<---            this code is formatted to fit into 80 columns             --->|
*/

import javax.sound.midi.*;
import java.io.File;
import java.io.IOException;


/**
 * <titleabbrev>LoopingMidiPlayer15</titleabbrev>
 * <title>Looping a MIDI file (JDK1.5 and later)</title>
 * <p/>
 * <formalpara><title>Purpose</title>
 * <p/>
 * <para>Loops a MIDI file using the new looping methods in the
 * Sequencer of the JDK1.5.</para></formalpara>
 * <p/>
 * <formalpara><title>Usage</title>
 * <para>
 * <cmdsynopsis>
 * <command>java LoopingMidiPlayer15</command>
 * <arg choice="plain"><replaceable>midifile</replaceable></arg>
 * </cmdsynopsis>
 * </para></formalpara>
 * <p/>
 * <formalpara><title>Parameters</title>
 * <variablelist>
 * <varlistentry>
 * <term><option><replaceable>midifile</replaceable></option></term>
 * <listitem><para>the name of the MIDI file that should be
 * played</para></listitem>
 * </varlistentry>
 * </variablelist>
 * </formalpara>
 * <p/>
 * <formalpara><title>Bugs, limitations</title>
 * <p/>
 * <para>This program always uses the default Sequencer and the default
 * Synthesizer to play on. For using non-default sequencers,
 * synthesizers or to play on an external MIDI port, see
 * <olink targetdoc="MidiPlayer"
 * targetptr="MidiPlayer">MidiPlayer</olink>.</para>
 * <p/>
 * <para>This program requires the JDK 1.5. For looping using the JDK
 * 1.4 or earlier, see <olink targetdoc="LoopingMidiPlayer14"
 * targetptr="LoopingMidiPlayer14">LoopingMidiPlayer14</olink>.</para>
 * <p/>
 * </formalpara>
 * <p/>
 * <formalpara><title>Source code</title>
 * <para>
 * <ulink url="LoopingMidiPlayer15.java.html">LoopingMidiPlayer15.java</ulink>
 * </para>
 * </formalpara>
 */
public class LoopingMidiPlayer15 {
    public static void main(String[] args)
            throws MidiUnavailableException, InvalidMidiDataException, IOException {
        final Sequencer sequencer;
        final Synthesizer synthesizer;

        /* We check if there is no command-line argument at all or the
           * first one is '-h'.  If so, we display the usage message and
           * exit.
           */
        if (args.length == 0 || args[0].equals("-h")) {
            printUsageAndExit();
        }

        String strFilename = args[0];
        File midiFile = new File(strFilename);

        /* We read in the MIDI file to a Sequence object.  This object
           * is set at the Sequencer later.
           */
        Sequence sequence = MidiSystem.getSequence(midiFile);

        /* Now, we need a Sequencer to play the sequence.  Here, we
           * simply request the default sequencer without an implicitly
           * connected synthesizer
           */
        sequencer = MidiSystem.getSequencer(false);

        /* The Sequencer is still a dead object.  We have to open() it
           * to become live.  This is necessary to allocate some
           * ressources in the native part.
           */
        sequencer.open();

        /* Next step is to tell the Sequencer which Sequence it has to
           * play. In this case, we set it as the Sequence object
           * created above.
           */
        sequencer.setSequence(sequence);

        /* We try to get the default synthesizer, open() it and chain
           * it to the sequencer with a Transmitter-Receiver pair.
           */
        synthesizer = MidiSystem.getSynthesizer();
        synthesizer.open();
        Receiver synthReceiver = synthesizer.getReceiver();
        Transmitter seqTransmitter = sequencer.getTransmitter();
        seqTransmitter.setReceiver(synthReceiver);

        /* To free system resources, it is recommended to close the
           * synthesizer and sequencer properly.
           *
           * To accomplish this, we register a Listener to the
           * Sequencer. It is called when there are "meta" events. Meta
           * event 47 is end of track.
           *
           * Thanks to Espen Riskedal for finding this trick.
           */
        sequencer.addMetaEventListener(new MetaEventListener() {
            public void meta(MetaMessage event) {
                if (event.getType() == 47) {
                    sequencer.close();
                    if (synthesizer != null) {
                        synthesizer.close();
                    }
                    //System.exit(0);
                }
            }
        });

        /* Here, we set the loop points to loop over the whole
           * sequence. Setting the loop end point to -1 means using the
           * last tick of the sequence as end point of the loop.
           *
           * Furthermore, we set the number of loops to loop infinitely.
           */
        sequencer.setLoopStartPoint(0);
        sequencer.setLoopEndPoint(-1);
        sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);

        /* Now, we can start over.
           */
        sequencer.start();
    }


    private static void printUsageAndExit() {
        out("LoopingMidiPlayer15: usage:");
        out("\tjava LoopingMidiPlayer15 <midifile>");
        System.exit(1);
    }


    private static void out(String strMessage) {
        System.out.println(strMessage);
    }
}


/*** LoopingMidiPlayer15.java ***/

